package com.zte.claa.inficombo.csa.app.service.modbus.impl;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zte.claa.inficombo.csa.app.dao.mysql.impl.ModbusMasterConfigMapper;
import com.zte.claa.inficombo.csa.app.dao.mysql.impl.ModbusRequestConfigMapper;
import com.zte.claa.inficombo.csa.app.dao.mysql.impl.ModbusResponseRelMapper;
import com.zte.claa.inficombo.csa.app.service.modbus.ModbusMainService;
import com.zte.claa.inficombo.csa.app.service.modbus.ModbusMasterService;
import com.zte.claa.inficombo.csa.app.service.modbus.ModbusMsgParser;
import com.zte.claa.inficombo.csa.app.service.modbus.ModbusMsgReceiver;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusMasterCommProps;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusMasterConfig;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusRequestConfig;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusResponseRelConfig;
import com.zte.claa.inficombo.csa.app.service.resrpt.ResIndexDataRptService;


@Service
public class ModbusMainServiceImpl implements ModbusMainService, InitializingBean, DisposableBean {
	
	private static final Logger logger = LoggerFactory.getLogger(ModbusMainServiceImpl.class);
		 
	//主站配置List
	private List<ModbusMasterConfig> masterConfigList = new ArrayList<>();
	//请求配置map
	private Map<String, List<ModbusRequestConfig>> requestConfigMap = new ConcurrentHashMap<>();	
	//响应映射map
	private Map<String, List<ModbusResponseRelConfig>> responseRelMap = new ConcurrentHashMap<>();
	
	private List<ModbusMasterService> mdbsList = new ArrayList<>();
		
	@Autowired
	private ModbusRequestConfigMapper requestConfigMapper;
	
	@Autowired
	private ModbusResponseRelMapper responseMapper;
	
	@Autowired
	private ModbusMasterConfigMapper masterConfigMapper;
	
	@Autowired
	private ModbusMasterCommProps modbusMasterCommProps; 
	
	@Autowired
	private ResIndexDataRptService resDataRptService;
				
	@Override
	public void afterPropertiesSet() throws Exception {
		new Thread(() -> init()).start();
	}
	
	
	@Override
	public void init(){
		try{
			initModbusMasterConfig();
			initModbusRequestConfig();
			initModbusResponseRel();
			//启动modbus主站任务
			launch();
			logger.info("Modbus master server load init config from db succ.");
		}catch (Exception e) {
			logger.error("Modbus master server failed to load init config from db." + e.getMessage());
		}			
	}
	
	
	//启动modbus主站任务
	private void launch() throws Exception{
		//清理资源,特别是线程池资源
		if(mdbsList != null && mdbsList.size() > 0){
			for(ModbusMasterService mdbs : mdbsList){
				try{
					mdbs.destory();
				}catch (Exception e) {
					continue;
				}			
			}
			mdbsList.clear();
		} 
		
		if(masterConfigList != null && masterConfigList.size() > 0){
			String configId = null;
			for(ModbusMasterConfig config : masterConfigList){
				try{
					configId = config.getMasterconfigid();
					
					//请求配置列表
					List<ModbusRequestConfig> requestConfigList = requestConfigMap.get(configId);
					if(requestConfigList == null || requestConfigList.size() == 0){
						continue;
					}
					
					//解析器映射
					Map<String, ModbusMsgParser> msgParserMap = new ConcurrentHashMap<>();
					for(ModbusRequestConfig req : requestConfigList){
						List<ModbusResponseRelConfig> responseConfigList = responseRelMap.get(req.getRequestid());				
						ModbusMsgParser msgParser = new ModbusMsgParserImpl(responseConfigList);
						msgParserMap.put(req.getRequestid(), msgParser);
					}
					
					//构造消息接收器,注入消息发布器
					ModbusMsgReceiver msgReceiver = new ModbusMsgReceiverImpl(resDataRptService,msgParserMap);
					//构造modbus服务
					ModbusMasterService mdbs = new ModbusMasterTcpServiceImpl(config,
																			modbusMasterCommProps,
																			requestConfigList,
																			msgReceiver);					
					//modbus主站初始化
					mdbs.init();
					mdbsList.add(mdbs);
					logger.info("Launch modbus master task successful -->" + config.getIp());
				}catch (Exception e) {
					logger.error("Launch modbus master task failed -->" + config.getIp() + ":" + e.getMessage());
					continue;
				}				
			}
		}		
	}
	
	
	//初始化modbus主站配置
	private void initModbusMasterConfig()throws Exception{
		 masterConfigList.clear();
		 masterConfigList = masterConfigMapper.selectAll();			
	}
		
				
	//初始化请求配置,将请求与主站配置1-N映射
	private void initModbusRequestConfig() throws Exception{		
		requestConfigMap.clear();
		List<ModbusRequestConfig> list = requestConfigMapper.selectAll();
		if (list != null && list.size() > 0){
			for(ModbusRequestConfig config : list){
				bindRequst2Master(config);
			}
		}		
	}
		
	private  void bindRequst2Master(ModbusRequestConfig config) throws Exception{
		if(config != null){
			String masterconfigId = config.getMasterconfigid();
			if(!requestConfigMap.containsKey(masterconfigId)){
				List<ModbusRequestConfig> list = new ArrayList<>();
				list.add(config);
				requestConfigMap.put(masterconfigId, list);
			}else{
				requestConfigMap.get(masterconfigId).add(config);
			}
		}	
	}
		
	
	//初始化响应映射
	private void initModbusResponseRel() throws Exception{
		responseRelMap.clear();
		List<ModbusResponseRelConfig> recordList = responseMapper.selectAll();
		if(recordList != null && recordList.size() > 0){
			for(ModbusResponseRelConfig record : recordList){
				if(responseRelMap.containsKey(record.getRequestid())){
					responseRelMap.get(record.getRequestid()).add(record);
				}else{
					List<ModbusResponseRelConfig> list = new ArrayList<>();
					list.add(record);
					responseRelMap.put(record.getRequestid(), list);				
				}
			}
		}		
	}


	@Override
	public void destroy() throws Exception{
		masterConfigList.clear();
		requestConfigMap.clear();
		responseRelMap.clear();
		for(ModbusMasterService mdbs : mdbsList){
			mdbs.destory();
		}
	}
	
}
